<?php

namespace app\utils;

class FileDownloader
{
    private $pemPath;
    private $url;
    private $savePath;
    private $callback;
    private $preDownloaded = -1;

    public function __construct($url, $savePath, $callback, $pemPath = null)
    {
        $this->url = $url;
        $this->savePath = $savePath;
        $this->callback = $callback;
        $this->pemPath = $pemPath;
    }

    public function download()
    {
        $this->preDownloaded = -1;
        $fp = fopen($this->savePath, 'w+');
        if ($fp === false) {
            throw new \Exception("Can not open file: " . $this->savePath);
        }

        $ch = curl_init($this->url);
        if ($ch === false) {
            throw new \Exception("cURL init fail");
        }

        curl_setopt($ch, CURLOPT_FILE, $fp);
        if($this->pemPath != null) {
            curl_setopt($ch, CURLOPT_CAINFO, $this->pemPath);
        }
        curl_setopt($ch, CURLOPT_NOPROGRESS, false);
        curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, [$this, 'progressCallback']);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_BUFFERSIZE, 128);
        curl_setopt($ch, CURLOPT_TIMEOUT, 0);

        $result = curl_exec($ch);

        if ($result === false) {
            $error = curl_error($ch);
            curl_close($ch);
            fclose($fp);
            throw new \Exception("download fail: " . $error);
        }

        curl_close($ch);
        fclose($fp);

        return true;
    }

    private function progressCallback($resource, $download_size, $downloaded, $upload_size, $uploaded)
    {
        if ($download_size > 0) {
            $progress = intval(($downloaded / $download_size) * 100);
            if ($progress != $this->preDownloaded) {
                $this->preDownloaded = $progress;
                call_user_func($this->callback, $progress);
            }
        }
    }
}